package cn.melonlib.cores.graphql.config.bean.impl;

import cn.melonlib.cores.commons.model.entity.IEntity;
import cn.melonlib.cores.graphql.comp.GraphQLSchemaTools;
import cn.melonlib.cores.graphql.comp.config.WorkerParametersReader;
import cn.melonlib.cores.graphql.comp.service.GraphQLService;
import cn.melonlib.cores.graphql.config.bean.GraphQLMutationWorker;
import cn.melonlib.cores.graphql.model.bean.GraphQLErrorBody;
import cn.melonlib.cores.graphql.model.bean.GraphQLMutationInfo;
import cn.melonlib.cores.jpa.model.bean.collections.EntityMap;
import cn.melonlib.cores.model.anno.WorkerLargeData;
import cn.melonlib.cores.model.anno.WorkerStore;
import graphql.schema.DataFetchingEnvironment;
import org.hibernate.jdbc.Work;
import org.springframework.context.support.ApplicationObjectSupport;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Component
public class DefaultGQLMutationWorker extends ApplicationObjectSupport implements GraphQLMutationWorker<GraphQLMutationInfo> {

    @Resource
    private GraphQLService graphQLService;

    @Resource
    private WorkerParametersReader workerParametersReader;

    @Resource
    private GraphQLSchemaTools graphQLSchemaTools;

    public GraphQLMutationInfo mutation(DataFetchingEnvironment env, Method mutationMethod, Object bean) throws Exception{
        WorkerStore mutation= AnnotationUtils.findAnnotation(mutationMethod, WorkerStore.class);
        List<Object> params = workerParametersReader.getReader(String.class).readParams(Arrays.stream(mutationMethod.getParameters())
                        .map(graphQLSchemaTools::getParameterName).collect(Collectors.toList())
                , mutationMethod,env,graphQLService,bean);
        try {
            Object [] execParams=new Object[mutationMethod.getParameterCount()];
            params.stream().reduce(0,(idx,param)->{
                execParams[idx]=param;
                return idx+1;
            },(idx,param)->null);
            Object res = mutationMethod.invoke(bean, execParams);
            StringBuilder message = new StringBuilder(mutation.successTip());
            if(res instanceof Integer){
                return GraphQLMutationInfo.createInfo(true, (Integer) res, message.toString(),"");
            }else if(res instanceof Collection){
                return GraphQLMutationInfo.createInfo(true, ((Collection)res).size(), message.toString(),"",((Collection<?>) res).stream().map(o->(IEntity)o).map(EntityMap::new).collect(Collectors.toList()));
            }else{
                if(res instanceof IEntity) {
                    WorkerLargeData workerLargeData=AnnotationUtils.findAnnotation(mutationMethod.getReturnType(), WorkerLargeData.class);
                    if(Objects.nonNull(workerLargeData)){
                        return GraphQLMutationInfo.createInfo(true, 1, message.toString(), "",  res);
                    }
                    return GraphQLMutationInfo.createInfo(true, 1, message.toString(), "", new EntityMap<>((IEntity<? extends Serializable>) res));
                }else{
                    return GraphQLMutationInfo.createInfo(true, 1, message.toString(), "",  res);
                }
            }
        }
        catch (InvocationTargetException exception){
            throw (Exception) exception.getTargetException();
        }
//        catch(Exception e){
//            StringBuilder message = new StringBuilder(mutation.errorTip());
//            if(mutation.showErrorMessage()){
//                message.append("，提示信息：").append(e.getMessage());
//            }
//            logger.error(e.getMessage(),e);
//            StringWriter exSw=new StringWriter();
//            e.getCause().printStackTrace(new PrintWriter(exSw));
//            return GraphQLMutationInfo.createInfo(false, 0, message.toString(),"",new GraphQLErrorBody(e.getCause().getMessage(), exSw.toString()));
//        }
    }
}
